import tkinter as tk
from tkinter import ttk, messagebox, filedialog, simpledialog
import pandas as pd
from datetime import datetime
import os
import sys
import webbrowser
import tempfile

class MainUI:
    def __init__(self, root, database, auth_manager):
        self.root = root
        self.db = database
        self.auth_manager = auth_manager
        self.current_user = None
    
    def set_current_user(self, user):
        """设置当前登录用户"""
        self.current_user = user
        # 登录成功后重新创建界面
        self.recreate_ui()
    
    def recreate_ui(self):
        """重新创建用户界面"""
        # 清除现有所有子组件
        for widget in self.root.winfo_children():
            widget.destroy()
        
        # 重新创建菜单和界面
        self.create_menu()
        self.create_widgets()
        
        # 添加Ctrl+S快捷键保存功能
        self.root.bind('<Control-s>', lambda event: self.save_info())
        self.root.bind('<Control-S>', lambda event: self.save_info())
    

    
    def create_menu(self):
        """创建主菜单"""
        # 创建菜单栏
        menubar = tk.Menu(self.root)
        
        # 创建文件菜单
        function_menu = tk.Menu(menubar, tearoff=0)
        function_menu.add_command(label="导出Excel", command=self.export_excel)
        function_menu.add_command(label="打印", command=self.print_current_content)
        menubar.add_cascade(label="文件", menu=function_menu)

        # 创建用户菜单
        user_menu = tk.Menu(menubar, tearoff=0)
        user_menu.add_command(label="忘记密码", command=lambda: self.auth_manager.create_forgot_password_window(None, self.set_current_user))
        menubar.add_cascade(label="用户", menu=user_menu)
        
        # 创建帮助菜单（可选）
        help_menu = tk.Menu(menubar, tearoff=0)
        help_menu.add_command(label="关于", command=self.show_about)
        help_menu.add_command(label="版本更新", command=self.show_website)
        help_menu.add_command(label="帮助文档", command=self.show_help)
        help_menu.add_command(label="联系我们", command=self.show_contact)
        menubar.add_cascade(label="帮助", menu=help_menu)
        
        # 设置菜单栏
        self.root.config(menu=menubar)

    def show_about(self):
        """显示关于信息"""
        messagebox.showinfo("关于", "小兔信息管理系统\n版本 1.1.6\n\n用于管理信息数据的应用程序") 

    def show_website(self):
        """查看最新版本"""
        webbrowser.open("https://fjtools.cn/index.php/xinxi.html")
        
    def show_help(self):
        """显示帮助文档"""
        webbrowser.open("https://www.fjtools.cn/index.php/archives/30/")
    
    def show_contact(self):
        """显示联系我们信息"""
        messagebox.showinfo("联系我们", "E-mail：\n3353360867@qq.com")
    
    def create_widgets(self):
        """创建界面组件"""
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        # 添加登录检查标签（临时显示，登录成功后会被刷新的界面覆盖）
        if not self.current_user:
            login_label = ttk.Label(main_frame, text="请先登录系统", font=("微软雅黑", 16))
            login_label.grid(row=0, column=0, pady=50, sticky=(tk.W, tk.E))
            return
        
        # 配置网格权重和宽度限制
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(0, weight=1, minsize=300)  # 信息列表区域
        main_frame.columnconfigure(1, weight=2, minsize=500)  # 信息录入区域至少500px
        main_frame.rowconfigure(1, weight=1)
        
        # 标题
        title_label = ttk.Label(main_frame, text="小兔信息管理系统", 
                               font=("微软雅黑", 16, "bold"))
        title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
        
        # 右侧：信息输入区域
        input_frame = ttk.LabelFrame(main_frame, text="信息录入", padding="10")
        input_frame.grid(row=1, column=1, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(10, 0))
        # 允许input_frame内部第1列扩展
        input_frame.columnconfigure(1, weight=1)
        # 设置行权重，使内容框行可以扩展
        input_frame.rowconfigure(3, weight=1)
        
        # 标签输入和按钮区域
        ttk.Label(input_frame, text="标签:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.category_entry = ttk.Entry(input_frame, width=40)  # 保持标签框长度
        self.category_entry.grid(row=0, column=1, sticky=(tk.W), pady=5, padx=(0, 10))  # 移除E扩展，固定宽度
        # 添加提示文本
        self.category_entry.insert(0, "多个标签用逗号分隔")
        
        # 初始化delete_btn但不显示，用于代码逻辑中的状态控制
        self.delete_btn = ttk.Button(input_frame, text="删除", command=self.delete_info, state="disabled")
        # delete_btn不会被grid显示，功能移至顶部菜单按钮
        
        # 添加保存状态提示标签，用于显示保存成功信息
        # 预留足够宽度显示"00:00 保存信息成功"文本
        self.save_status_label = ttk.Label(input_frame, text="", foreground="green", font=('SimHei', 9), width=30)
        self.save_status_label.grid(row=0, column=2, sticky=tk.W, pady=5, padx=5)
        
        # 标题
        ttk.Label(input_frame, text="标题:").grid(row=1, column=0, sticky=tk.W, pady=5)
        self.title_entry = ttk.Entry(input_frame)
        self.title_entry.grid(row=1, column=1, columnspan=3, sticky=(tk.W, tk.E), pady=5)
        
        # 内容输入
        ttk.Label(input_frame, text="内容:").grid(row=3, column=0, sticky=tk.NW, pady=5)
        # 创建垂直滚动条
        self.content_scrollbar = ttk.Scrollbar(input_frame, orient=tk.VERTICAL)
        # 创建内容框并关联滚动条
        self.content_text = tk.Text(input_frame, font=('SimSun', 11), yscrollcommand=self.content_scrollbar.set)
        # 配置滚动条控制内容框
        self.content_scrollbar.config(command=self.content_text.yview)
        # 布局内容框和滚动条
        self.content_text.grid(row=3, column=1, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
        self.content_scrollbar.grid(row=3, column=4, sticky=(tk.N, tk.S), pady=5)
        # 设置文本标签配置
        self.content_text.tag_config("default", lmargin1=0, lmargin2=0, spacing1=5, spacing2=5, spacing3=5)
        self.content_text.tag_add("default", "1.0", "end")
        
        # 左侧：信息显示区域
        display_frame = ttk.LabelFrame(main_frame, text="信息列表", padding="10", width=450)
        display_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        display_frame.columnconfigure(0, weight=1)
        display_frame.rowconfigure(1, weight=1)
        display_frame.grid_propagate(False)  # 防止frame大小被内容撑开
        
        # 搜索区域
        search_frame = ttk.Frame(display_frame)
        search_frame.grid(row=0, column=0, sticky=(tk.W, tk.E), pady=(0, 10))
        
        ttk.Label(search_frame, text="搜索:").pack(side=tk.LEFT)
        self.search_entry = ttk.Entry(search_frame, width=20)  # 缩短搜索框长度
        self.search_entry.pack(side=tk.LEFT, padx=5)
        self.search_entry.bind('<KeyRelease>', self.search_info)
        # 添加标签云按钮到搜索框右侧
        self.tag_cloud_btn = ttk.Button(search_frame, text="标签云", command=self.show_tag_cloud)
        self.tag_cloud_btn.pack(side=tk.LEFT, padx=5)
        # 添加"+"按钮到标签云按钮右侧，带下拉菜单
        self.menu_button = ttk.Menubutton(search_frame, text="+")
        self.menu_button.pack(side=tk.LEFT, padx=5)
        # 创建下拉菜单
        self.main_menu = tk.Menu(self.menu_button, tearoff=0)
        self.main_menu.add_command(label="新建", command=self.clear_form)
        self.main_menu.add_command(label="保存", command=self.save_info)
        self.main_menu.add_command(label="删除", command=self.delete_info)
        self.main_menu.add_command(label="打印", command=self.print_current_content)
        # 关联菜单到按钮
        self.menu_button.configure(menu=self.main_menu)
        
        # 信息列表（移除ID列和类型列，将分类改为标签）
        columns = ("标题", "标签", "创建时间")
        self.tree = ttk.Treeview(display_frame, columns=columns, show="headings", height=15)
        
        # 设置列宽（标题列 = 原ID列宽度 + 原标题列宽度）
        self.tree.column("标题", width=165)  # 25 + 140 = 165
        self.tree.column("标签", width=50)
        self.tree.column("创建时间", width=60)
        
        # 设置列标题
        for col in columns:
            self.tree.heading(col, text=col)
        
        self.tree.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        self.tree.bind('<<TreeviewSelect>>', self.on_item_select)
        
        # 滚动条
        scrollbar = ttk.Scrollbar(display_frame, orient=tk.VERTICAL, command=self.tree.yview)
        scrollbar.grid(row=1, column=1, sticky=(tk.N, tk.S))
        self.tree.configure(yscrollcommand=scrollbar.set)

        
                
        # 加载数据
        self.load_data()
    
    def save_info(self, event=None):
        """保存信息（根据是否有选中项判断是添加还是更新）"""
        title = self.title_entry.get().strip()
        tags = self.category_entry.get().strip()
        content = self.content_text.get("1.0", tk.END).strip()
        
        if not title:
            messagebox.showerror("错误", "请输入标题！")
            return
            
        selection = self.tree.selection()
        is_update_operation = len(selection) > 0
        update_item_id = selection[0] if is_update_operation else None
        
        try:
            if not is_update_operation:
                # 没有选中项，执行添加操作
                current_time = datetime.now().strftime("%Y-%m-%d")
                # 插入数据
                self.db.cursor.execute('''
                    INSERT INTO information (user_id, title, content, category, create_time)
                    VALUES (?, ?, ?, ?, ?)
                ''', (self.current_user['id'], title, content, tags, current_time))
                self.db.commit()
            else:
                # 有选中项，执行更新操作
                # 更新数据
                self.db.cursor.execute('''
                    UPDATE information 
                    SET title=?, content=?, category=?, update_time=CURRENT_TIMESTAMP
                    WHERE id=? AND user_id=?
                ''', (title, content, tags, update_item_id, self.current_user['id']))
                
                if self.db.cursor.rowcount == 0:
                    messagebox.showerror("错误", "无法更新此信息，可能无权操作！")
                    return
                    
                self.db.commit()
            
            # 重新加载数据以更新列表，但不清空当前编辑内容
            self.load_data()
            
            # 保存成功后显示时间提示，包含时、分、秒
            current_time = datetime.now().strftime("%H:%M:%S")
            self.save_status_label.config(text=f"{current_time} 保存信息成功")
            
            # 3秒后自动清空提示信息
            self.root.after(3000, lambda: self.save_status_label.config(text=""))
            
            # 如果是更新操作，重新选中刚才编辑的项目，以便再次保存时仍视为更新
            if is_update_operation and update_item_id:
                # 检查item是否存在于tree中（可能由于权限变更而不存在）
                if update_item_id in self.tree.get_children():
                    self.tree.selection_set(update_item_id)
                    self.tree.focus(update_item_id)
                    # 滚动到选中的项目
                    self.tree.see(update_item_id)
            
        except Exception as e:
            messagebox.showerror("错误", f"保存失败：{str(e)}")
    
    def print_current_content(self):
        """打印当前编辑框中的标题和内容"""
        title = self.title_entry.get().strip()
        content = self.content_text.get("1.0", tk.END).strip()
        tags = self.category_entry.get().strip()
        
        if not title and not content:
            messagebox.showinfo("提示", "没有可打印的内容")
            return
        
        try:
            # 创建打印对话框
            print_window = tk.Toplevel(self.root)
            print_window.title(f"打印预览 - {title if title else '无标题'}")
            print_window.geometry("700x650")
            print_window.minsize(700, 650)
            
            # 设置网格布局
            print_window.grid_rowconfigure(0, weight=1)
            print_window.grid_columnconfigure(0, weight=1)
            
            # 创建预览文本框
            preview_text = tk.Text(print_window, wrap=tk.WORD, font=('微软雅黑', 12))
            preview_text.grid(row=0, column=0, sticky='nsew', padx=20, pady=20)
            
            # 添加滚动条
            scrollbar = ttk.Scrollbar(print_window, command=preview_text.yview)
            scrollbar.grid(row=0, column=1, sticky='ns', pady=20)
            preview_text.config(yscrollcommand=scrollbar.set)
            
            # 生成打印内容
            print_content = f"""{title if title else '无标题'}
标签: {tags if tags else '无标签'}

{content if content else '无内容'}"""
            preview_text.insert(tk.END, print_content)
            preview_text.config(state=tk.DISABLED)  # 只读
            
            # 创建底部按钮区域
            bottom_frame = ttk.Frame(print_window)
            bottom_frame.grid(row=1, column=0, columnspan=2, sticky='ew', padx=20, pady=10)
            center_frame = ttk.Frame(bottom_frame)
            center_frame.pack(anchor=tk.CENTER)
            
            # 创建打印任务
            def do_print():
                temp_filename = None
                try:
                    # 创建临时文件
                    temp_filename = tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False).name
                    
                    # 写入文件（使用UTF-8编码）
                    with open(temp_filename, 'w', encoding='utf-8') as f:
                        f.write(print_content)
                    
                    # 使用系统默认程序打开文件
                    if sys.platform.startswith('win'):
                        os.startfile(temp_filename, 'print')
                    elif sys.platform.startswith('darwin'):  # macOS
                        os.system(f'open -a "Preview" "{temp_filename}"')
                    else:  # Linux
                        os.system(f'xdg-open "{temp_filename}"')
                    
                    messagebox.showinfo("成功", "打印任务已提交")
                    
                except Exception as e:
                    messagebox.showerror("打印错误", f"打印过程中发生错误: {str(e)}")
                finally:
                    print_window.destroy()
                    # 延迟删除临时文件，让打印任务有时间读取
                    if temp_filename:
                        def delete_temp():
                            try:
                                if os.path.exists(temp_filename):
                                    os.unlink(temp_filename)
                            except:
                                pass
                        print_window.after(5000, delete_temp)  # 5秒后删除
            
            # 创建确认打印按钮
            confirm_btn = ttk.Button(center_frame, text='确认打印', command=do_print, width=15)
            confirm_btn.pack(side=tk.LEFT, padx=20)
            
            # 创建取消按钮
            cancel_btn = ttk.Button(center_frame, text='取消', command=print_window.destroy, width=15)
            cancel_btn.pack(side=tk.LEFT, padx=20)
            
        except Exception as e:
            messagebox.showerror("错误", "加载打印预览失败：" + str(e))

    def delete_info(self):
        """删除信息"""
        selection = self.tree.selection()
        if not selection:
            return
            
        if not messagebox.askyesno("确认", "确定要删除这条信息吗？"):
            return
            
        # 使用id获取原始数据库ID，而不是显示的序号
        item_id = selection[0]
        
        try:
            # 删除时确保只删除当前用户的信息
            self.db.cursor.execute('DELETE FROM information WHERE id=? AND user_id=?', (item_id, self.current_user['id']))
            
            if self.db.cursor.rowcount == 0:
                messagebox.showerror("错误", "无法删除此信息，可能无权操作！")
                return
                
            self.db.commit()
            
            messagebox.showinfo("成功", "信息删除成功！")
            self.clear_form()
            self.load_data()
            
        except Exception as e:
            messagebox.showerror("错误", f"删除失败：{str(e)}")

    def search_info(self, event=None):
        """搜索信息"""
        keyword = self.search_entry.get().strip()
        
        if not keyword:
            self.load_data()
            return
            
        try:
            # 搜索时只搜索当前用户的信息
            self.db.cursor.execute('''
                SELECT id, title, category, create_time 
                FROM information 
                WHERE user_id=? AND (title LIKE ? OR content LIKE ? OR category LIKE ?)
                ORDER BY create_time DESC
            ''', (self.current_user['id'], f'%{keyword}%', f'%{keyword}%', f'%{keyword}%'))
            
            rows = self.db.cursor.fetchall()
            self.display_data(rows)
            
        except Exception as e:
            messagebox.showerror("错误", f"搜索失败：{str(e)}")

    def load_data(self):
        """加载当前用户的数据"""
        try:
            # 只加载当前用户的信息
            self.db.cursor.execute('''
                SELECT id, title, category, create_time 
                FROM information 
                WHERE user_id=?
                ORDER BY create_time DESC
            ''', (self.current_user['id'],))
            self.display_data()
            
        except Exception as e:
            messagebox.showerror("错误", f"加载数据失败：{str(e)}")

    def display_data(self, rows=None):
        """在Treeview中显示数据，为每个用户生成独立的序号"""
        # 清空现有数据
        for item in self.tree.get_children():
            self.tree.delete(item)
            
        # 如果没有传入数据，则从cursor获取
        if rows is None:
            rows = self.db.cursor.fetchall()
            
        # 添加新数据，在标题前添加圆点符号
        for row in rows:
            # 格式化创建时间，只显示年月日
            create_time = row[3]
            if create_time and isinstance(create_time, str) and len(create_time) > 10:
                create_time = create_time[:10]  # 只取年月日部分
            # 将原始数据库ID存储在item的iid中，在标题前添加圆点符号
            title_with_dot = f"• {row[1]}"
            self.tree.insert("", tk.END, iid=row[0], values=(title_with_dot, row[2], create_time))

    def on_item_select(self, event):
        """选中项时的处理"""
        selection = self.tree.selection()
        if not selection:
            return
            
        # 使用iid获取原始数据库ID，而不是显示的序号
        item_id = selection[0]
        
        try:
            # 查询详情时确保只查询当前用户的信息
            self.db.cursor.execute('SELECT title, content, category, create_time, update_time FROM information WHERE id=? AND user_id=?', (item_id, self.current_user['id']))
            result = self.db.cursor.fetchone()
            
            if result:
                # 更新表单
                self.title_entry.delete(0, tk.END)
                self.title_entry.insert(0, result[0])  # title
                self.category_entry.delete(0, tk.END)                
                self.category_entry.insert(0, result[2] if result[2] else "")  # category
                self.content_text.delete("1.0", tk.END)                
                self.content_text.insert("1.0", result[1] if result[1] else "")  # content
                self.content_text.tag_add("default", "1.0", "end")  # 重新应用行距样式
                
                # 更新按钮状态
                self.delete_btn.config(state="normal")
                
                # 格式化创建时间，只显示年月日
                create_time_display = result[3]
                if create_time_display and isinstance(create_time_display, str) and len(create_time_display) > 10:
                    create_time_display = create_time_display[:10]  # 只取年月日部分
                
                # 格式化更新时间，只显示年月日
                update_time_display = result[4]
                if update_time_display and isinstance(update_time_display, str) and len(update_time_display) > 10:
                    update_time_display = update_time_display[:10]  # 只取年月日部分
                
                # 标签云功能不需要在选择时显示详细信息
            else:
                # 如果找不到该信息（可能是其他用户的），清除表单
                self.clear_form()
                messagebox.showinfo("提示", "无法访问此信息")
                
        except Exception as e:
            messagebox.showerror("错误", f"加载详情失败：{str(e)}")

    def show_tag_cloud(self):
        """显示标签云弹出窗口"""
        # 创建弹出窗口
        self.tag_cloud_window = tk.Toplevel(self.root)
        self.tag_cloud_window.title("标签云")
        self.tag_cloud_window.geometry("600x400")
        self.tag_cloud_window.resizable(False, False)
        
        # 创建标签云容器
        tag_frame = ttk.LabelFrame(self.tag_cloud_window, text="所有标签", padding="10")
        tag_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 创建垂直滚动条
        scrollbar = ttk.Scrollbar(tag_frame, orient=tk.VERTICAL)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 创建Canvas作为可滚动区域
        self.tag_canvas = tk.Canvas(tag_frame, yscrollcommand=scrollbar.set)
        self.tag_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        # 配置滚动条
        scrollbar.config(command=self.tag_canvas.yview)
        
        # 创建内部框架放置标签
        self.tag_cloud_frame = ttk.Frame(self.tag_canvas)
        
        # 在Canvas上创建窗口
        self.tag_canvas.create_window((0, 0), window=self.tag_cloud_frame, anchor="nw")
        
        # 绑定大小变化事件
        def on_configure(event):
            # 只更新Canvas的滚动区域，不重新加载标签云以避免递归
            self.tag_canvas.configure(scrollregion=self.tag_canvas.bbox("all"))
        
        # 仅为Canvas绑定配置事件
        self.tag_canvas.bind("<Configure>", on_configure)
        
        # 添加一个调整大小的处理函数，但使用延迟执行避免递归
        resize_timer_id = None
        last_width = 0  # 记录上一次的窗口宽度
        
        def on_window_resize(event):
            nonlocal resize_timer_id, last_width
            # 只有当窗口宽度变化超过20像素时才重新布局，避免频繁刷新
            current_width = event.width
            if abs(current_width - last_width) > 20 or last_width == 0:
                last_width = current_width
                # 取消之前的定时器
                if resize_timer_id:
                    self.tag_cloud_window.after_cancel(resize_timer_id)
                # 设置新的定时器，延迟重新布局
                resize_timer_id = self.tag_cloud_window.after(300, self.rearrange_tags)
        
        # 为窗口绑定大小变化事件
        self.tag_cloud_window.bind("<Configure>", on_window_resize)
        
        # 初始化按钮引用字典，用于重新布局
        self.tag_buttons = {}
        # 初始化按钮容器框架
        self.buttons_container = None
        # 加载标签云
        self.load_tag_cloud()
    
    def load_tag_cloud(self):
        """加载标签云"""
        # 清除现有标签
        for widget in self.tag_cloud_frame.winfo_children():
            widget.destroy()
        
        # 清空按钮引用字典
        self.tag_buttons.clear()
        
        # 获取所有唯一标签
        try:
            # 注意：category字段存储的是用逗号分隔的标签列表
            self.db.cursor.execute('''
                SELECT DISTINCT category FROM information WHERE user_id = ?
            ''', (self.current_user['id'],))
            categories = self.db.cursor.fetchall()
            
            # 解析所有标签，创建唯一标签集合
            unique_tags = set()
            for category in categories:
                if category[0]:
                    tags = [tag.strip() for tag in category[0].split(',') if tag.strip()]
                    unique_tags.update(tags)
            
            # 创建一个容器框架来放置按钮
            self.buttons_container = ttk.Frame(self.tag_cloud_frame)
            self.buttons_container.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
            
            # 获取按钮的平均宽度（估算值）
            from tkinter import font
            
            # 创建所有按钮并存储引用
            for tag_name in sorted(unique_tags):
                tag_button = ttk.Button(self.buttons_container, text=tag_name,
                                      command=lambda t=tag_name: self.on_tag_click(t))
                # 存储按钮引用，键为标签名
                self.tag_buttons[tag_name] = tag_button
            
            # 初始布局
            self.rearrange_tags()
            
        except Exception as e:
            messagebox.showerror("错误", f"加载标签云失败：{str(e)}")
            
    def rearrange_tags(self):
        """重新排列标签按钮，实现自动换行"""
        # 获取当前框架的宽度
        frame_width = 0
        if hasattr(self, 'tag_cloud_window') and self.tag_cloud_window.winfo_exists():
            # 获取框架可用宽度，减去一些边距
            frame_width = self.tag_cloud_frame.winfo_width() - 20
            if frame_width <= 0:
                # 如果宽度不可用，使用默认值
                frame_width = 550
        else:
            frame_width = 550
        
        # 首先将所有按钮从父组件中移除（但不销毁）
        for btn in self.tag_buttons.values():
            if btn.winfo_ismapped():
                btn.grid_forget()
        
        # 使用流式布局（一行一行地放置按钮）
        current_row = 0
        row_buttons = []
        
        # 计算每个按钮的估算宽度（基于文本长度）
        button_widths = {}
        for tag_name in self.tag_buttons:
            # 每个字符8像素，加上40像素的边框和内边距，再加10像素的边距
            button_widths[tag_name] = len(tag_name) * 8 + 50
        
        # 按照实际宽度进行布局
        for tag_name, btn in sorted(self.tag_buttons.items()):
            # 获取按钮的估算宽度
            btn_width = button_widths.get(tag_name)
            
            # 计算当前行已用宽度
            current_row_width = 0
            for btn_in_row in row_buttons:
                btn_in_row_name = [key for key, value in self.tag_buttons.items() if value == btn_in_row][0]
                current_row_width += button_widths.get(btn_in_row_name) + 10  # 加上间距
            
            # 检查是否需要换行
            if row_buttons and current_row_width + btn_width + 10 > frame_width:  # 加上新按钮和间距后的总宽度
                # 换行处理
                current_row += 1
                row_buttons = []
            
            # 放置按钮
            btn.grid(row=current_row, column=len(row_buttons), padx=5, pady=5, sticky="w")
            row_buttons.append(btn)
        
        # 更新Canvas的滚动区域
        if hasattr(self, 'tag_canvas'):
            self.tag_cloud_frame.update_idletasks()
            self.tag_canvas.configure(scrollregion=self.tag_canvas.bbox("all"))
    
    def on_tag_click(self, tag_name):
        """点击标签时的处理，过滤显示对应标签的信息"""
        try:
            # 搜索该标签的信息
            self.db.cursor.execute('''
                SELECT id, title, category, create_time 
                FROM information 
                WHERE user_id=? AND category LIKE ?
                ORDER BY create_time DESC
            ''', (self.current_user['id'], f'%{tag_name}%'))
            rows = self.db.cursor.fetchall()
            self.display_data(rows)
            
        except Exception as e:
            messagebox.showerror("错误", f"搜索标签信息失败：{str(e)}")
    
    def clear_form(self):
        """清空表单"""
        self.title_entry.delete(0, tk.END)
        self.category_entry.delete(0, tk.END)
        self.category_entry.insert(0, "多个标签用逗号分隔")  # 添加标签提示
        self.content_text.delete("1.0", tk.END)
        self.content_text.tag_add("default", "1.0", "end")  # 重新应用行距样式
        self.delete_btn.config(state="disabled")
        self.tree.selection_remove(self.tree.selection())
        # 清空保存状态提示信息
        self.save_status_label.config(text="")

    def export_excel(self):
        """导出到Excel"""
        try:
            # 选择保存路径
            filename = filedialog.asksaveasfilename(
                defaultextension=".xlsx",
                filetypes=[("Excel文件", "*.xlsx"), ("所有文件", "*.*")],
                initialfile=f"小兔信息_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
            )
            
            if not filename:
                return
                
            # 读取当前用户的数据
            df = pd.read_sql_query('''
                SELECT category as 标签, title as 标题, 
                       content as 内容, create_time as 创建时间, update_time as 更新时间
                FROM information 
                WHERE user_id=?
                ORDER BY create_time DESC
            ''', self.db.conn, params=(self.current_user['id'],))
            
            # 导出到Excel
            df.to_excel(filename, index=False, engine='openpyxl')
            messagebox.showinfo("成功", f"数据已导出到：{filename}")
            
        except Exception as e:
            messagebox.showerror("错误", f"导出失败：{str(e)}")